

// 缓冲区模块设计
// 为异步日志器提供方服务
// 异步日志器使用双缓冲区
#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__

#include <iostream>
#include <vector>
#include <cassert>

namespace xglog
{
#define DEFAULT_BUFFER_SIZE (10 * 1024 * 1024)
#define THRESHOLD_BUFFER_SIZE (80 * 1024 * 1024)
#define INCREMENT_BUFFER_SIZE (10 * 1024 * 1024)
    class Buffer
    {
    public:
        Buffer()
            : _buffer(DEFAULT_BUFFER_SIZE), _write_idx(0), _read_idx(0)
        {
        }
        // 向缓冲区中添加长度为len的数据
        void push(const char *data, size_t len)
        {
            // 如果空间不足，可以选择扩容，也可以选择阻塞住
            //(1)阻塞
            //  if(_write_idx+len<_buffer.size())
            //  {
            //      return;
            //  }
            //(2)扩容,这里使用一种类似于网络中拥塞控制的慢开始算法
            ensureEnough(len);

            // 1,向缓冲区中添加长度为len的数据(直接使用拷贝的方法)
            std::copy(data, data + len, &_buffer[_write_idx]);
            // 2,写位置向后移动len个长度
            moveWrite(len);
        }
        // 重置缓冲区位置
        void reset()
        {
            _write_idx = 0;
            _read_idx = 0;
        }
        // 交换缓冲区
        //bug问题所在,没有加&
        //交换缓冲区时产生拷贝
        //导致生产缓冲区一直没有被交换,交换的一直都是生产缓冲区的拷贝
        void swap(Buffer& buffer)
        {
            // 在这里交换地址即可
            _buffer.swap(buffer._buffer);
            std::swap(_write_idx, buffer._write_idx);
            std::swap(_read_idx, buffer._read_idx);
        }
        // 获取当前缓冲区可以读的起始位置
        // 也就是数据的起始位置
        char *begin()
        {
            return &_buffer[_read_idx];
        }
        // 当前缓冲区可以写数据的空间大小
        size_t writeAbleSize()
        {
            return _buffer.size() - _write_idx;
        }
        // 当前缓冲区可以读数据的空间大小
        size_t readAbleSize()
        {
            return _write_idx - _read_idx;
        }
        // 读位置的移动
        void moveRead(size_t len)
        {
            assert(len < _buffer.size());
            _read_idx += len;
        }

        // 写位置的移动
        void moveWrite(size_t len)
        {
            assert(len < _buffer.size());
            _write_idx += len;
        }
        //判断缓冲区是否为空
        //经典的生产者消费者模型
        bool empty()
        {
            return _write_idx==_read_idx;
        }

    private:
        // 使用慢开始的扩容方式
        // 超过阈值时线性增长,达到前期增长块，后期增长慢
        void ensureEnough(size_t len)
        {
            if (len < writeAbleSize())
                return;

            size_t newsize = 0;
            if (_buffer.size() <= THRESHOLD_BUFFER_SIZE)
                newsize = _buffer.size() * 2; // 小于阈值翻倍增长
            else
                newsize = _buffer.size() + INCREMENT_BUFFER_SIZE; // 超过阈值,线性增长

            _buffer.resize(newsize);
        }
    private:
        // 缓冲区数组
        std::vector<char> _buffer;
        // 当前写数据的位置
        size_t _write_idx;
        // 当前读数据的位置
        size_t _read_idx;
    };
}

#endif